package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
)

// 在线用户
var onlineUsersMap map[string]*Client

// 全局聊天室消息通道
var messageChan = make(chan string)

type Client struct {
	c    chan string // 消息管道
	Name string      // 名字
	Addr string      // ip以及端口
}

func main() {
	listen, err := net.Listen("tcp", "127.0.0.1:8000")
	if err != nil {
		fmt.Println("listen err", err)
		return
	}
	defer listen.Close()

	go Manager()

	for {
		conn, err := listen.Accept()
		if err != nil {
			fmt.Println("accept err", err)
			return
		}
		go HandleConnect(conn)
	}
}

func HandleConnect(conn net.Conn) {
	defer conn.Close()

	// 创建client并添加进在线用户列表
	netAddr := conn.RemoteAddr().String()
	client := &Client{make(chan string), netAddr, netAddr}
	onlineUsersMap[netAddr] = client
	// 启动新client的消息检测转发
	go writeMsgToClient(client, conn)
	// 广播上线消息
	messageChan <- MakeMsg(client, "login", false)
	// 用户活跃检测
	hasData := make(chan bool)
	// 用户退出管道
	isQuit := make(chan bool)

	// 消息处理匿名go程
	go func() {
		buf := make([]byte, 4096)
		for {
			n, err := conn.Read(buf)
			if n == 0 {
				isQuit <- true
				fmt.Printf("用户[%s]:%s已退出\n", client.Addr, client.Name)
				return
			}
			if err != nil {
				fmt.Println("read err", err)
				return
			}

			msg := string(buf[:n-1])
			if msg == "/who" {
				conn.Write([]byte("online users:\n"))
				for _, user := range onlineUsersMap {
					userInfo := user.Addr + ":" + user.Name + "\n"
					conn.Write([]byte(userInfo))
				}
			} else if len(msg) >= 9 && msg[:7] == "/rename" {
				newName := strings.Split(msg, " ")[1]
				newName = strings.TrimSpace(newName)
				client.Name = newName
				conn.Write([]byte("Rename success\n"))
			} else if strings.TrimSpace(msg) == "/help" {
				command := `
All command:
/who: Show all online user
/rename newName: modify nickname
/whisper port: Talk privately with port client
/whether cityid: Today's weather 
`

				conn.Write([]byte(command))
			} else if len(msg) >= 10 && msg[:8] == "/whisper" {
				aimClientAddr := "127.0.0.1:" + strings.Split(msg, " ")[1]
				if clnt, ok := onlineUsersMap[aimClientAddr]; !ok {
					conn.Write([]byte("User does not exist!\n"))
				} else {
					msg := MakeMsg(client, strings.SplitAfterN(msg, " ", 3)[2], true)
					clnt.c <- msg
					client.c <- msg
				}
			} else if len(msg) >= 10 && msg[:8] == "/whether" {
				cityid := strings.SplitAfterN(msg, " ", 2)[1]
				// 101180301新乡
				url := fmt.Sprintf("https://www.yiketianqi.com/free/day?appid=47163346&appsecret=JIwqoSE5&unescape=1&cityid=%s", cityid)
				fmt.Println(url)
				resp, err := http.Get(url)
				if err != nil {
					conn.Write([]byte("查询失败！"))
				} else {
					whether := make(map[string]interface{})
					bytes, err := ioutil.ReadAll(resp.Body)
					if err != nil {
						fmt.Println(err, "读取失败")
					}
					temp := string(bytes)
					errUnMarshal := json.Unmarshal([]byte(temp), &whether)
					if errUnMarshal != nil {
						fmt.Println(errUnMarshal)
					}
					fmt.Println(temp)
					fmt.Println(&whether)
					str := fmt.Sprintf("%v:\nwhether: %v\nCurrent Temperature: %v C\nTemperature Range: %v~%v C\nUpdate-time: %v\n", whether["cityid"], whether["wea_img"], whether["tem"], whether["tem_night"], whether["tem_day"], whether["update_time"])
					conn.Write([]byte(str))
				}
			} else {
				messageChan <- MakeMsg(client, msg, false)
			}
			hasData <- true
		}
	}()
	for {
		select {
		// 退出后发消息
		case <-isQuit:
			delete(onlineUsersMap, client.Addr)
			messageChan <- MakeMsg(client, "logout", false)
			return
		// 活跃检测
		case <-hasData:

			//超时退出
			//case <-time.After(time.Second * 20):
			//	delete(onlineUsersMap, client.Addr)
			//	messageChan <- MakeMsg(client, "logout", false)
			//	return
		}
	}

}

func MakeMsg(client *Client, msg string, isWhisper bool) (buf string) {
	if isWhisper {
		buf = "Whisper:" + "[" + client.Addr + "]" + client.Name + ":" + msg + "\n"
	} else {
		buf = "[" + client.Addr + "]" + client.Name + ": " + msg + "\n"
	}
	return
}

func writeMsgToClient(client *Client, conn net.Conn) {
	for msg := range client.c {
		conn.Write([]byte(msg))
	}
}

func Manager() {
	// 在线用户列表
	onlineUsersMap = make(map[string]*Client)

	// 全局消息监视转发
	for {
		msg := <-messageChan
		for _, client := range onlineUsersMap {
			client.c <- msg
		}
	}
}
